#if defined(WIN32) || defined(_WIN32)

#include "Select.h"
#include "../reactor/Reactor.h"

using namespace std;
using namespace network;

Select::Select() {
    FD_ZERO(&master_read_set_);
    timeout_.tv_sec = 0;
    timeout_.tv_sec = 0;
    max_fd_ = 0;
}

bool Select::add(int fd, EventType event) {
    if (hasEvent(event, EventType::Read)) {
        FD_SET(fd, &master_read_set_);
    } else if (hasEvent(event, EventType::Write)) {
        FD_SET(fd, &master_write_set_);
    }
    max_fd_ = max(fd, max_fd_);
    return true;
}

bool Select::mod(int fd, EventType event) {
    if (hasEvent(event, EventType::Read)) {
        FD_CLR(fd, &master_write_set_);
        FD_SET(fd, &master_read_set_);
    } else if (hasEvent(event, EventType::Write)) {
        FD_CLR(fd, &master_read_set_);
        FD_SET(fd, &master_write_set_);
    }
    max_fd_ = max(fd, max_fd_);
    return true;
}

bool Select::del(int fd) {
    FD_CLR(fd, &master_read_set_);
    return false;
}

int Select::dispatch(Reactor *reactor) {
    read_set_ = master_read_set_;
    write_set_ = master_write_set_;
    int ret = select(max_fd_ + 1, &read_set_, &write_set_, nullptr, &timeout_);
    if (ret < 0) {
        throw runtime_error("select return < 0");
    }
    for (int fd = 0; fd <= max_fd_; ++fd) {
        if (FD_ISSET(fd, &read_set_)) {
            reactor->addEvent(fd, EventType::Read);
        } else if (FD_ISSET(fd, &write_set_)) {
            reactor->addEvent(fd, EventType::Write);
        }
    }
    return ret;
}

#endif
